// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2025-02-25

package consul

import (
	"encoding/json"
	"fmt"
	"gitee.com/go-libs/console"
	"github.com/valyala/fasthttp"
	"net/http"
)

// Key
// 注册在Consul中的Key名称.
//
// 假设你在浏览器中编辑的URL为 `http://example.com/ui/dc1/kv/go-apps/gomq/db.yaml/edit`,
// 则此时其值为 `go-apps/gomq/db.yaml` 或 `go-apps/gomq`. 若Key的值指向目录, 目录下的文件
// 或子目录及文件也会一并下载到本地.
//
//	k1 := Key("globals/mysql/charset")
//	k2 := Key("go-apps/gmq")
type Key string

// Get
// 以HTTP的GET方式从Consul读取Key列表.
func (o Key) Get(container *console.Container, host string) (list []*Entity, err error) {
	var (
		request  = fasthttp.AcquireRequest()
		response = fasthttp.AcquireResponse()
	)

	// 1. 监听结束.
	defer func() {
		// 1.1 捕获异常.
		if r := recover(); r != nil {
			container.GetOutput().Fatal(`  - {%s}: %v`, o, r)

			if err == nil {
				err = fmt.Errorf(`%v`, r)
			}
		} else {
			if err != nil {
				container.GetOutput().Error(`  - {%s}: %v`, o, err)
			} else {
				container.GetOutput().Info(`  - {%s}`, o)
			}
		}

		// 1.2 释放资源.
		fasthttp.ReleaseRequest(request)
		fasthttp.ReleaseResponse(response)
	}()

	// 2. 准备请求.
	request.Header.SetMethod(http.MethodGet)
	request.Header.SetRequestURI(o.buildUrl(host))
	request.Header.SetContentType("application/json")

	// 3. 请求过程.
	if err = fasthttp.Do(request, response); err != nil {
		return
	}

	// 4. 返回错误.
	if code := response.StatusCode(); code != http.StatusOK {
		err = fmt.Errorf(`HTTP %d %s`, code, http.StatusText(code))
		return
	}

	// 5. 构建结果.
	list = make([]*Entity, 0)
	err = json.Unmarshal(response.Body(), &list)
	return
}

// IsBlank
// 是否为空.
func (o Key) IsBlank() bool { return o.String() == "" }

// IsDir
// 是否为目录.
func (o Key) IsDir() bool { return regexEndWithSlash.MatchString(o.String()) }

// IsYaml
// 是否为YAML文件.
//
// 若Key的名称以 `.yml` 或 `.yaml` 结尾, 则返回true.
func (o Key) IsYaml() bool { return regexYamlFile.MatchString(o.String()) }

// String
// 返回Key的字符串名称.
func (o Key) String() string { return string(o) }

// +---------------------------------------------------------------------------+
// |                                  Access                                   |
// +---------------------------------------------------------------------------+

// buildUrl
// 生成应用于API的Key地址, 用于从Consul读取其值.
//
//	http://localhost:8500/v1/kv/go-apps/gomq?recurse=true
//	http://localhost:8500/v1/kv/go-apps/gomq/db.yaml?recurse=true
func (o Key) buildUrl(host string) string {
	return fmt.Sprintf(`%s/v1/kv/%s?recurse=true`, host, o)
}
